package com.acme.domain.account;

import com.acme.exceptions.OverDraftLimitExceededException;

import java.math.BigDecimal;

public class CheckingAccount extends AbstractAccount {
    private BigDecimal overdraft;
    private final BigDecimal maxCredit;

    public CheckingAccount(final BigDecimal amount, final BigDecimal overdraft) {
        super(amount);
        this.overdraft = overdraft;
        this.maxCredit = overdraft;
    }

    @Override
    public void withdraw(BigDecimal x) throws OverDraftLimitExceededException {
        if (x.compareTo(maximumAmountToWithdraw()) > 0) {
            throw new OverDraftLimitExceededException(getBalance());
        }
        if (getBalance().compareTo(x) >= 0) {
            setBalance(getBalance().subtract(x));
        } else if (getBalance().add(overdraft).compareTo(x) >= 0) {
            x = x.subtract(getBalance());
            setBalance(BigDecimal.ZERO);
            overdraft = overdraft.subtract(x);
        }
    }

    public BigDecimal maximumAmountToWithdraw() {
        return getBalance().add(overdraft);
    }

    @Override
    public void deposit(final BigDecimal amount) {
        if (amount.compareTo(BigDecimal.ZERO) > 0) {
            setBalance(getBalance().add(amount));
        } else {
            throw new IllegalArgumentException("amount ca not be negative");
        }
    }

    @Override
    public AccountType getAccountType() {
        return AccountType.CHECKING;
    }

    public BigDecimal getOverdraft() {
        return overdraft;
    }

    public BigDecimal getCredit() {
        return maxCredit.subtract(overdraft);
    }

    @Override
    public String toString() {
        return String.format("Checking account with amount: %s$ and overdraft %s$", getBalance(), overdraft);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        CheckingAccount that = (CheckingAccount) o;

        if (getBalance() != null ? !getBalance().equals(that.getBalance()) : that.getBalance() != null) return false;
        if (overdraft != null ? !overdraft.equals(that.overdraft) : that.overdraft != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = (getBalance() != null ? getBalance().hashCode() : 0);
        result = 31 * result + (overdraft != null ? overdraft.hashCode() : 0);
        return result;
    }
}